import {
  buffer,
  bufferCount,
  bufferTime,
  bufferToggle,
  bufferWhen,
  concatMap,
  defer,
  EMPTY,
  exhaustMap,
  expand,
  from,
  fromEvent,
  fromEventPattern,
  interval,
  map,
  mergeMap,
  of,
  pluck,
  switchMap,
  take,
} from "rxjs";

const obj = {
  name: "zhangsan",
  age: 18,
};

// expand 主要相当于递归调用；
// 把 expand((val) => of(val + 1)) 会一直运行
export function expandDemo() {
  const ofObs = of(1);

  ofObs
    .pipe(
      expand((val) => of(val + 1)),
      take(10),
    )
    .subscribe((x) => {
      console.log(x);
    });
}

// 模拟一个异步请求，返回一个 Observable
const simulateRequest = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(obj);
    }, 2000);
  }).then((response) => response);
};

// 实现一个防止重复提交
export function exhaustMapDemo() {
  // simulateRequest().then((res) => {
  //   console.log(res);
  // });
  //
  const click$ = fromEvent(document, "click");
  // 防止重复点击
  // click$.pipe(exhaustMap(() => interval(500).pipe(take(2)))).subscribe((x) => {
  //   console.log(x);
  // });
  //
  // const promiseData = simulateRequest().then(res => res);

  //  把promise对象转成 Observable 对象
  const promiseObs = defer(() => simulateRequest());
  // 防止重复请求
  click$.pipe(exhaustMap(() => promiseObs)).subscribe((x) => {
    console.log(x);
  });
}

const closeBUfferObs = () => {
  // 产生一个 2000-5000 之间的的随机数
  const randomTime = Math.floor(Math.random() * (5000 - 2000 + 1) + 2000);
  return interval(randomTime).pipe(take(1));
};

// 产生一个2-5 秒之前的随机数，并把buffer 的数据打印出来
export function bufferWhenDemo() {
  const intervalObs = interval(500); // 0.5 s 产生一个数据
  intervalObs.pipe(bufferWhen(closeBUfferObs)).subscribe((x) => {
    console.log("bufferValue is %s", x);
  });
}

export function bufferToggerDemo() {
  console.log("bufferToggerDemo");

  const click$ = fromEvent(document, "click");

  click$
    .pipe(
      bufferToggle(interval(1000), (i) =>
        i % 2 === 0 ? EMPTY : interval(500),
      ),
    )
    .subscribe((x) => {
      console.log(x);
    });
}

// bufferTime, 就是 2s 内必须消费数据，不管有没有数据；
export function bufferTimeDemo() {
  const click$ = fromEvent(document, "click");
  // click$.pipe(bufferTime(2000).subscribe((x) => console.log(x));
  // 前2s的时间不算，每5s执行一次
  click$.pipe(bufferTime(2000, 5000)).subscribe((x) => console.log(x));
}

// bufferCount 】篮子中的数据达到某个值的时候自动取出来
export function bufferCountDemo() {
  const intervalObs = interval(200);
  intervalObs.pipe(bufferCount(3, 2)).subscribe((x) => console.log(x));
}

// buffer
// 把数据装在一个篮子里面，当buffer中的obserable触发的时候，取出篮子中的数据；
export function bufferDemo() {
  const intervalObs = interval(500);
  const click$ = fromEvent(document, "click");
  intervalObs.pipe(buffer(click$)).subscribe((x) => {
    console.log(x);
  });
}

// ------ 以下比较重要，必须要会的 ------
// 这个方法过期了，目前可以使用map 来代替；这玩意只能接受一个参数;
export function pluckDemo() {
  const ofObs = from([
    { name: "zhangsan", age: 18 },
    { name: "lisisi", age: 20 },
  ]);

  // ofObs.pipe(pluck("name")).subscribe((a) => console.log(a));
  ofObs.pipe(map((val) => val.age)).subscribe((a) => console.log(a));
}

export function switchMapDemo() {
  const ofObs = of(1, 2, 3);

  // 把上面的做个转换
  ofObs
    .pipe(
      switchMap((x) => {
        // 回调函数中必须返回一个obserable
        return of(x + 1, x + 2, x + 3);
      }),
    )
    .subscribe((x) => {
      console.log(x); // 2,3,4 3,4,5 4,5,6
    });
}

export function mergeMapDemo() {
  const ofObs = of("a", "b", "c");

  // mergeMap: 把ofObs和其它的Observerable合并
  ofObs
    .pipe(
      mergeMap((c: string) => {
        return interval(200).pipe(
          take(4),
          map((x) => c + "---" + x),
        );
      }),
    )
    .subscribe((x) => console.log(x));
}

// concatMap 和 map 的不同点； concatMap 返回的是一个observable, 这个observable
// 中的值会放在 subscribe中， map
// 中直接把返回一个值，这个值做为subscribe中的参数；
export function concatmapDemo() {
  const click$ = fromEvent(document, "click");

  click$
    .pipe(concatMap((ev) => interval(1000).pipe(take(3))))
    .subscribe((x) => {
      console.log(x);
    });
}
